/*
 * This file is part of JFlowMap.
 *
 * Copyright 2009 Ilya Boyandin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jflowmap;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.SwingWorker;

import jflowmap.data.ViewConfig;
import jflowmap.ui.export.ExporterWindow;
import jflowmap.ui.export.IExporterWindow;
import jflowmap.ui.export.decorators.FileChooserDecorator;
import jflowmap.ui.export.decorators.RendererChooserDecorator;
import jflowmap.util.HelpTextSwitcher;
import jflowmap.util.SwingUtils;
import jflowmap.util.piccolo.PBoxLayoutNode;
import jflowmap.util.piccolo.PButton;
import jflowmap.views.IView;
import jflowmap.views.VisualCanvas;

import org.apache.log4j.Logger;

import at.fhj.utils.misc.FileUtils;
import at.fhj.utils.swing.JMsgPane;

import com.google.common.collect.ImmutableList;

import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;


/**
 * @author Ilya Boyandin
 */
public class ViewLoader {

	private static Logger logger = Logger.getLogger(ViewLoader.class);

	public static final String CLIENT_PROPERTY_CONTAINER_IVIEW = "_iview";
	public static final ImageIcon LOADING_ICON = JFlowMapMain.createImageIcon("ui/resources/fons.png");
	private static final Font LOADING_TEXT_FONT = new Font("Sans Serif", Font.PLAIN, 13);


	public static boolean isApplet(Component c) {
		return (SwingUtils.getAppletFor(c) != null);
	}

	public static void loadView(final String viewConfigLocation, final Container parent)
			throws Exception
			{
		final JLabel loadingLabel = new JLabel(" Lade '" +
				FileUtils.getFilename(viewConfigLocation) + "'...", LOADING_ICON, JLabel.CENTER);
		loadingLabel.setFont(LOADING_TEXT_FONT);
		parent.add(loadingLabel);
		parent.setBackground(Color.white);

		SwingWorker<IView, Object> worker = new SwingWorker<IView, Object>() {
			ViewConfig config;

			@Override
			public IView doInBackground() throws Exception {
				config = ViewConfig.load(viewConfigLocation, parent);
				adjustWindowSize(parent);
				return config.createView();
			}

			private void adjustWindowSize(final Container parent) {
				String size = config.getString(ViewConfig.PROP_WINDOW_SIZE);
				if (size != null) {
					Matcher m = Pattern.compile("(\\d+)x(\\d+)").matcher(size);
					if (m.matches()) {
						Dimension dim = new Dimension(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)));

						JInternalFrame iframe = SwingUtils.getInternalFrameFor(parent);
						if (iframe != null) {
							iframe.setSize(dim);
						} else {
							Window win = SwingUtils.getWindowFor(parent);
							if (win != null) {
								win.setSize(dim);
							}
						}
					}
				}
			}

			@Override
			protected void done() {
				boolean isViewEmpty = true;
				try {

					IView view = get();
					if (view != null) {
						/*
            JComponent controls = view.getControls();
            if (controls != null) {
              parent.add(controls, view.getControlsLayoutConstraint());
            }
						 */

						VisualCanvas canvas = view.getVisualCanvas();
						if (canvas != null) {
							parent.add(canvas, BorderLayout.CENTER);
							isViewEmpty = false;

							JInternalFrame iframe = SwingUtils.getInternalFrameFor(parent);
							
							if (iframe != null) {
								iframe.setTitle(view.getName());
								iframe.putClientProperty(CLIENT_PROPERTY_CONTAINER_IVIEW, view);
								
							} else {
								Window w = SwingUtils.getWindowFor(parent);
								w.addWindowListener(canvas.getWindowListener());
								w.setName(view.getName());
							}

							final JComponent controls = view.getControls();
							//if (controls != null) {
							initControls(parent, canvas, controls, config);
							//}

							canvas.repaint();
						}
					}
					/*
          Applet applet = SwingUtils.getAppletFor(view.getVisualCanvas());
          if (applet != null   &&   applet instanceof JFlowMapApplet) {
            ((JFlowMapApplet)applet).jsFlowMapViewLoaded();
          }*/

				} catch (Exception ex) {
					logger.error("Cannot open view", ex);
					ex.printStackTrace();
					JMsgPane.showProblemDialog(parent, ex.getMessage());
					isViewEmpty = true;
				} finally {
					
					try {
						parent.remove(loadingLabel);
						if (isViewEmpty) {
							parent.add(new JLabel("No view", JLabel.CENTER), BorderLayout.CENTER);
						}
						parent.validate();
						
						
					} catch (Exception ex) {
						// ignore
					}
				}
			}
		};
		worker.execute();
			}

	private static void initControls(final Container parent, VisualCanvas canvas,
			final JComponent controls, ViewConfig config) {


		String visibleTabs = config.getString(ViewConfig.PROP_WINDOW_SETTINGS_SHOW_TABS);
		if (visibleTabs != null) {
			setVisibileSettingsTabs(controls, visibleTabs.split(","));
		}

		boolean embedSettings = config.getBoolOrElse(ViewConfig.PROP_WINDOW_SETTINGS_EMBED, true);

		PBoxLayoutNode buttonPanel = canvas.getSettingButtonsPanel();
		buttonPanel.removeAllChildren();
		
		if (controls != null && embedSettings == false) {
			buttonPanel.addChild(createSettingsButton(parent, controls, config));
		} else if (controls != null){
			parent.add(controls, BorderLayout.SOUTH);
		}
		
		buttonPanel.addChild(createPaintToPdfButton(parent, canvas));
		buttonPanel.addChild(createHelpTextButton(parent, canvas));
	}

	private static PButton createHelpTextButton (final Container container, final VisualCanvas canvas) {
		final PButton help = new PButton("?", true);
		help.setPressed(true);
		canvas.getHelpText().helpFor(help, new HelpTextSwitcher() {
			@Override
			public String getHelpText() {
				return "Hilfesystem aktiviert. Zum Deaktivieren hier klicken!";
			}
		});

		help.addInputEventListener(new PBasicInputEventHandler() {
			@Override
			public void mouseClicked(PInputEvent event) {
				if (help.isPressed()) {
					canvas.getHelpText().activate();
				} else {
					canvas.getHelpText().deactivate();
				}
			} 
		});

		return help;
	}

	private static PButton createPaintToPdfButton(final Container container, final VisualCanvas canvas) {
		PButton but = new PButton("PDF");
		canvas.getHelpText().helpFor(but, new HelpTextSwitcher() {
			@Override
			public String getHelpText() {
				return "Aktuellen Kartenausschnitt und Kommentare als PDF exportieren";
			}
		});

		but.addInputEventListener(new PBasicInputEventHandler() {
			@Override
			public void mouseClicked(PInputEvent event) {

				/*JFileChooser fc = new JFileChooser();
				fc.setDialogTitle("Als PDF exportieren");
				fc.setApproveButtonText("Speichern");
				fc.setFileFilter(new FileFilter() {

					@Override
					public boolean accept(File f) {
						if (f.getName().endsWith(".pdf"))
							return true;
						else
							return false;
					}

					@Override
					public String getDescription() {
						return "PDF-Dateien";
					}
				});

				int retVal = fc.showOpenDialog(container);

				if (retVal == JFileChooser.APPROVE_OPTION) {
					File f = fc.getSelectedFile();
					canvas.tryToPaintToPdf(f);
					if (!f.getName().endsWith(".pdf")) {
						f.renameTo(new File(f.getAbsolutePath() + ".pdf"));
					}
				}*/
				IExporterWindow exporter = 
						new RendererChooserDecorator(
						new FileChooserDecorator(ExporterWindow.create(null, null)));
				
				exporter.setVisible(true);
			}
		});
		return but;
	}

	private static PButton createSettingsButton(final Container parent, final JComponent controls,
			ViewConfig config) {
		final PButton settingsBut = new PButton("Ansicht", true);

		Window win = SwingUtils.getWindowFor(parent);
		final JDialog dialog = new JDialog(win, "Ansicht");
		//    try {
		//      dialog.setAlwaysOnTop(true);
		//    } catch (SecurityException se) {
		//      // ignore
		//    }
		dialog.setContentPane(controls);
		dialog.pack();
		Rectangle b = win.getBounds();
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		dialog.setLocation(
				(int)b.getMaxX() - dialog.getWidth(),
				(int)Math.min(b.getMaxY(), screen.getHeight() - dialog.getHeight()));
		dialog.setResizable(false);


		String activeTab = config.getString(ViewConfig.PROP_WINDOW_SETTINGS_ACTIVE_TAB);
		if (activeTab != null) {
			setActiveControlTab(dialog.getContentPane(), activeTab);
		}

		boolean visible = config.getBoolOrElse(ViewConfig.PROP_WINDOW_SETTINGS_SHOW, true);
		dialog.setVisible(visible);
		settingsBut.setPressed(visible);

		settingsBut.addInputEventListener(new PBasicInputEventHandler() {
			@Override
			public void mouseClicked(PInputEvent event) {
				if (!dialog.isVisible()) {
					dialog.setVisible(true);
					dialog.toFront();
					dialog.requestFocus();
					dialog.addWindowListener(new WindowAdapter() {
						@Override
						public void windowDeactivated(WindowEvent e) {
							if (!settingsBut.isArmed()) {
								settingsBut.setPressed(false);
							}
						}
						@Override
						public void windowClosed(WindowEvent e) {
						}
					});
				} else {
					dialog.setVisible(false);
				}
			}
		});

		return settingsBut;
	}

	private static JTabbedPane getTabbedPane(Container contentPane) {
		JTabbedPane tp = null;
		for (Component c : contentPane.getComponents()) {
			if (c instanceof JTabbedPane) {
				tp = (JTabbedPane)c;
				break;
			}
		}
		return tp;
	}

	private static void setActiveControlTab(Container contentPane, String activeTab) {
		JTabbedPane tp = getTabbedPane(contentPane);
		if (tp != null) {
			int index = tp.indexOfTab(activeTab);
			if (index >= 0) {
				tp.setSelectedIndex(index);
			}
		}
	}

	private static int setVisibileSettingsTabs(Container contentPane, String[] visibleTabs) {
		int numVisible = 0;
		List<String> tabList = ImmutableList.copyOf(visibleTabs);
		JTabbedPane tp = getTabbedPane(contentPane);
		if (tp != null) {
			for (int i = tp.getTabCount() - 1; i >= 0; i--) {
				String title = tp.getTitleAt(i);
				boolean visible = tabList.contains(title);
				if (!visible) {
					tp.removeTabAt(i);
				} else {
					numVisible++;
				}
			}

			if (tp.getTabCount() == 1) {
				Component onlyTab = tp.getComponentAt(0);
				contentPane.remove(tp);
				contentPane.add(onlyTab);
			}
		}
		return numVisible;
	}

}
